<?php
/**
 * 用户服务层
 *
 * @author Claude Code
 * @since 2025-11-03
 */

namespace app\service;

use app\model\admin\User;
use app\model\admin\Department;
use app\model\admin\Position;
use app\model\admin\AdminGroup;
use app\model\lawyer\Lawyer;
use think\facade\Db;
use think\facade\Cache;
use think\exception\ValidateException;

/**
 * 用户业务逻辑处理
 *
 * 主要职责：
 * 1. 用户数据的增删改查
 * 2. 业务规则验证
 * 3. 数据关联处理
 * 4. 缓存管理
 */
class UserService
{
    /**
     * 用户模型
     * @var User
     */
    protected $userModel;

    /**
     * 部门模型
     * @var Department
     */
    protected $departmentModel;

    /**
     * 职位模型
     * @var Position
     */
    protected $positionModel;

    /**
     * 权限组模型
     * @var AdminGroup
     */
    protected $groupModel;

    /**
     * 律师模型
     * @var Lawyer
     */
    protected $lawyerModel;

    /**
     * 缓存键前缀
     */
    protected const CACHE_PREFIX = 'user:';

    /**
     * 缓存过期时间
     */
    protected const CACHE_EXPIRE = 3600;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->userModel = new User();
        $this->departmentModel = new Department();
        $this->positionModel = new Position();
        $this->groupModel = new AdminGroup();
        $this->lawyerModel = new Lawyer();

        // 开启模型缓存
        $this->userModel->withCache(self::CACHE_EXPIRE, self::CACHE_PREFIX . 'model');
    }

    /**
     * 获取用户列表（带部门、职位信息）
     *
     * @param array $params 查询参数
     * @param int $page 页码
     * @param int $limit 每页数量
     * @return array
     * @throws \Exception
     */
    public function getUserList(array $params = [], int $page = 1, int $limit = 15): array
    {
        try {
            // 使用预加载避免N+1查询
            $query = $this->userModel
                ->with(['department', 'position', 'group'])
                ->where(function ($q) use ($params) {
                    $this->buildSearchConditions($q, $params);
                });

            // 获取总数
            $total = $query->count();

            // 分页数据
            $list = $query->page($page, $limit)
                ->order('id', 'desc')
                ->select();

            // 处理数据（添加文本字段）
            foreach ($list as &$user) {
                $user['department_name'] = $user->department?->getAttr('title') ?? '';
                $user['position_name'] = $user->position?->getAttr('title') ?? '';
                $user['group_name'] = $user->group?->getAttr('title') ?? '';
                $user['status_text'] = $this->getStatusText($user['status']);
                $user['sex_text'] = $this->getSexText($user['sex']);
                $user['user_type_text'] = $this->getUserTypeText($user['user_type']);
            }

            // 清除内存引用
            unset($user);

            return [
                'list' => $list,
                'total' => $total,
                'page' => $page,
                'limit' => $limit
            ];
        } catch (\Exception $e) {
            throw new \Exception('获取用户列表失败：' . $e->getMessage());
        }
    }

    /**
     * 构建搜索条件
     *
     * @param \think\db\Query $query 查询对象
     * @param array $params 参数
     * @return void
     */
    protected function buildSearchConditions($query, array $params): void
    {
        // 关键词搜索
        if (!empty($params['keywords'])) {
            $keyword = '%' . trim($params['keywords']) . '%';
            $query->where(function ($q) use ($keyword) {
                $q->where('name', 'like', $keyword)
                  ->whereOr('username', 'like', $keyword)
                  ->whereOr('mobile', 'like', $keyword)
                  ->whereOr('email', 'like', $keyword);
            });
        }

        // 姓名筛选
        if (!empty($params['name'])) {
            $query->where('name', 'like', '%' . $params['name'] . '%');
        }

        // 用户名筛选
        if (!empty($params['username'])) {
            $query->where('username', 'like', '%' . $params['username'] . '%');
        }

        // 手机号筛选
        if (!empty($params['mobile'])) {
            $query->where('mobile', 'like', '%' . $params['mobile'] . '%');
        }

        // 状态筛选
        if (isset($params['status']) && $params['status'] !== '') {
            $query->where('status', $params['status']);
        }

        // 部门筛选
        if (!empty($params['did'])) {
            $query->where('did', $params['did']);
        }

        // 职位筛选
        if (!empty($params['position_id'])) {
            $query->where('position_id', $params['position_id']);
        }

        // 权限组筛选
        if (!empty($params['group_id'])) {
            $query->where('group_id', $params['group_id']);
        }

        // 用户类型筛选
        if (isset($params['user_type']) && $params['user_type'] !== '') {
            $query->where('user_type', $params['user_type']);
        }

        // 性别筛选
        if (isset($params['sex']) && $params['sex'] !== '') {
            $query->where('sex', $params['sex']);
        }

        // 日期范围筛选
        if (!empty($params['start_date'])) {
            $query->where('create_time', '>=', strtotime($params['start_date']));
        }
        if (!empty($params['end_date'])) {
            $query->where('create_time', '<=', strtotime($params['end_date'] . ' 23:59:59'));
        }
    }

    /**
     * 获取用户详情
     *
     * @param int $id 用户ID
     * @return array|null
     * @throws \Exception
     */
    public function getUserById(int $id): ?array
    {
        try {
            // 使用缓存提高性能
            $cacheKey = self::CACHE_PREFIX . 'info_' . $id;
            $user = Cache::get($cacheKey);

            if ($user === null) {
                $user = $this->userModel
                    ->with(['department', 'position', 'group', 'lawyer'])
                    ->find($id);

                if ($user) {
                    $user = $user->toArray();
                    // 添加文本字段
                    $user['department_name'] = $user['department']['title'] ?? '';
                    $user['position_name'] = $user['position']['title'] ?? '';
                    $user['group_name'] = $user['group']['title'] ?? '';
                    $user['status_text'] = $this->getStatusText($user['status']);
                    $user['sex_text'] = $this->getSexText($user['sex']);

                    // 缓存数据
                    Cache::set($cacheKey, $user, self::CACHE_EXPIRE);
                }
            }

            return $user ?: null;
        } catch (\Exception $e) {
            throw new \Exception('获取用户详情失败：' . $e->getMessage());
        }
    }

    /**
     * 创建用户
     *
     * @param array $data 用户数据
     * @return int 用户ID
     * @throws \Exception
     */
    public function createUser(array $data): int
    {
        try {
            // 数据验证
            $this->validateUserData($data);

            // 检查用户名唯一性
            if ($this->userModel->checkUsernameExists($data['username'])) {
                throw new \Exception('用户名已存在');
            }

            // 检查部门是否存在
            if (!empty($data['did'])) {
                $department = $this->departmentModel->find($data['did']);
                if (!$department) {
                    throw new \Exception('部门不存在');
                }
            }

            // 检查职位是否存在
            if (!empty($data['position_id'])) {
                $position = $this->positionModel->find($data['position_id']);
                if (!$position) {
                    throw new \Exception('职位不存在');
                }
            }

            // 自动生成数据
            $data = $this->autoGenerateUserData($data);

            // 开启事务
            Db::startTrans();

            // 插入用户
            $userId = $this->userModel->insertGetId($data);

            // 提交事务
            Db::commit();

            // 清除相关缓存
            $this->clearUserCache($userId);

            return $userId;
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            throw new \Exception('创建用户失败：' . $e->getMessage());
        }
    }

    /**
     * 更新用户
     *
     * @param int $id 用户ID
     * @param array $data 用户数据
     * @return bool
     * @throws \Exception
     */
    public function updateUser(int $id, array $data): bool
    {
        try {
            // 检查用户是否存在
            $user = $this->userModel->find($id);
            if (!$user) {
                throw new \Exception('用户不存在');
            }

            // 数据验证
            $this->validateUserData($data, $id);

            // 检查用户名唯一性
            if (isset($data['username']) &&
                $this->userModel->checkUsernameExists($data['username'], $id)) {
                throw new \Exception('用户名已存在');
            }

            // 检查部门是否存在
            if (isset($data['did']) && !empty($data['did'])) {
                $department = $this->departmentModel->find($data['did']);
                if (!$department) {
                    throw new \Exception('部门不存在');
                }
            }

            // 检查职位是否存在
            if (isset($data['position_id']) && !empty($data['position_id'])) {
                $position = $this->positionModel->find($data['position_id']);
                if (!$position) {
                    throw new \Exception('职位不存在');
                }
            }

            // 开启事务
            Db::startTrans();

            // 处理密码
            if (!empty($data['password'])) {
                $salt = get_salt(20);
                $data['salt'] = $salt;
                $data['pwd'] = md5(md5($data['password'] . $salt) . $salt);
                $data['reg_pwd'] = $data['password'];
                unset($data['password']);
            }

            $data['update_time'] = time();

            $result = $this->userModel->where('id', $id)->update($data) > 0;

            // 提交事务
            Db::commit();

            // 清除相关缓存
            $this->clearUserCache($id);

            return $result;
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            throw new \Exception('更新用户失败：' . $e->getMessage());
        }
    }

    /**
     * 删除用户
     *
     * @param int $id 用户ID
     * @return bool
     * @throws \Exception
     */
    public function deleteUser(int $id): bool
    {
        try {
            // 检查用户是否存在
            $user = $this->userModel->find($id);
            if (!$user) {
                throw new \Exception('用户不存在');
            }

            // 检查是否有下级用户
            $childCount = $this->userModel->where('pid', $id)->count();
            if ($childCount > 0) {
                throw new \Exception('该用户下存在子用户，无法删除');
            }

            // 检查是否有关联的案件
            $lawcaseCount = Db::table('oa_lawcase')->where('admin_id|lawyer_id', $id)->count();
            if ($lawcaseCount > 0) {
                throw new \Exception('该用户下存在关联案件，无法删除');
            }

            // 开启事务
            Db::startTrans();

            // 软删除用户
            $result = $this->userModel->destroy($id) > 0;

            // 提交事务
            Db::commit();

            // 清除相关缓存
            $this->clearUserCache($id);

            return $result;
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            throw new \Exception('删除用户失败：' . $e->getMessage());
        }
    }

    /**
     * 批量删除用户
     *
     * @param array $ids 用户ID数组
     * @return int 删除数量
     * @throws \Exception
     */
    public function batchDeleteUser(array $ids): int
    {
        if (empty($ids)) {
            return 0;
        }

        try {
            Db::startTrans();

            $deleteCount = 0;
            foreach ($ids as $id) {
                if ($this->deleteUser($id)) {
                    $deleteCount++;
                }
            }

            Db::commit();

            return $deleteCount;
        } catch (\Exception $e) {
            Db::rollback();
            throw new \Exception('批量删除用户失败：' . $e->getMessage());
        }
    }

    /**
     * 验证用户数据
     *
     * @param array $data 数据
     * @param int $id 用户ID（更新时使用）
     * @throws ValidateException
     */
    protected function validateUserData(array $data, int $id = 0): void
    {
        if (empty($data['name'])) {
            throw new ValidateException('用户姓名不能为空');
        }

        if (isset($data['email']) && !empty($data['email']) &&
            !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
            throw new ValidateException('邮箱格式不正确');
        }

        if (isset($data['mobile']) && !empty($data['mobile']) &&
            !preg_match('/^1[3-9]\d{9}$/', $data['mobile'])) {
            throw new ValidateException('手机号格式不正确');
        }

        if ($id === 0 && empty($data['username'])) {
            throw new ValidateException('用户名不能为空');
        }

        if (isset($data['did']) && empty($data['did'])) {
            throw new ValidateException('请选择部门');
        }

        if (isset($data['position_id']) && empty($data['position_id'])) {
            throw new ValidateException('请选择职位');
        }
    }

    /**
     * 自动生成用户数据
     *
     * @param array $data 原始数据
     * @return array
     */
    protected function autoGenerateUserData(array $data): array
    {
        // 自动生成用户名
        if (empty($data['username'])) {
            $data['username'] = $this->generateUsername($data['name']);
        }

        // 生成默认密码
        if (empty($data['reg_pwd'])) {
            $data['reg_pwd'] = $this->generateRandomPassword(6);
        }

        // 处理密码
        $salt = get_salt(20);
        $data['salt'] = $salt;
        $data['pwd'] = md5(md5($data['reg_pwd'] . $salt) . $salt);

        // 生成默认头像
        if (empty($data['thumb'])) {
            $data['thumb'] = $this->generateAvatar($data['name']);
        }

        // 设置默认值
        $data['status'] = $data['status'] ?? 1;
        $data['user_type'] = $data['user_type'] ?? 1;
        $data['sex'] = $data['sex'] ?? 0;
        $data['is_lock'] = $data['is_lock'] ?? 0;
        $data['login_num'] = $data['login_num'] ?? 0;
        $data['create_time'] = time();
        $data['update_time'] = time();

        return $data;
    }

    /**
     * 生成用户名
     *
     * @param string $name 姓名
     * @return string
     */
    protected function generateUsername(string $name): string
    {
        // 尝试将中文名转换为拼音
        if (function_exists('pinyin')) {
            $username = pinyin($name, false);
        } else {
            // 如果没有pinyin函数，使用简单的转换
            $username = $this->simplePinyin($name);
        }

        if (empty($username)) {
            $username = 'user' . time();
        }

        // 确保唯一性
        $baseUsername = $username;
        $suffix = 1;
        while ($this->userModel->checkUsernameExists($username)) {
            $username = $baseUsername . $suffix;
            $suffix++;
        }

        return $username;
    }

    /**
     * 简单拼音转换
     *
     * @param string $name 姓名
     * @return string
     */
    protected function simplePinyin(string $name): string
    {
        $pinyinMap = [
            '张' => 'zhang', '李' => 'li', '王' => 'wang', '刘' => 'liu', '陈' => 'chen',
            '杨' => 'yang', '赵' => 'zhao', '黄' => 'huang', '周' => 'zhou', '吴' => 'wu',
            // ... 其他常见姓氏
        ];

        $pinyin = '';
        $length = mb_strlen($name, 'UTF-8');

        for ($i = 0; $i < $length; $i++) {
            $char = mb_substr($name, $i, 1, 'UTF-8');
            $pinyin .= $pinyinMap[$char] ?? $char;
        }

        return strtolower(preg_replace('/[^a-z0-9]/', '', $pinyin));
    }

    /**
     * 生成随机密码
     *
     * @param int $length 长度
     * @return string
     */
    protected function generateRandomPassword(int $length = 8): string
    {
        $chars = 'abcdefghijkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789';
        $password = '';
        for ($i = 0; $i < $length; $i++) {
            $password .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $password;
    }

    /**
     * 生成默认头像
     *
     * @param string $name 姓名
     * @return string
     */
    protected function generateAvatar(string $name): string
    {
        $char = mb_substr($name, 0, 1, 'UTF-8');
        $colors = ['3498db', '2ecc71', 'e74c3c', 'f39c12', '9b59b6', '1abc9c', '#34495e'];
        $color = $colors[ord($char) % count($colors)];
        return "https://ui-avatars.com/api/?name=" . urlencode($char) . "&background={$color}&color=ffffff&size=128";
    }

    /**
     * 获取状态文本
     *
     * @param int $status 状态值
     * @return string
     */
    protected function getStatusText(int $status): string
    {
        $statusMap = [
            -1 => '待入职',
            0 => '禁用',
            1 => '正常',
            2 => '离职'
        ];
        return $statusMap[$status] ?? '未知';
    }

    /**
     * 获取性别文本
     *
     * @param int $sex 性别值
     * @return string
     */
    protected function getSexText(int $sex): string
    {
        $sexMap = [
            0 => '未知',
            1 => '男',
            2 => '女'
        ];
        return $sexMap[$sex] ?? '未知';
    }

    /**
     * 获取用户类型文本
     *
     * @param int $userType 用户类型
     * @return string
     */
    protected function getUserTypeText(int $userType): string
    {
        $typeMap = [
            1 => '内部员工',
            2 => '外联律师'
        ];
        return $typeMap[$userType] ?? '未知';
    }

    /**
     * 清除用户相关缓存
     *
     * @param int $userId 用户ID
     * @return void
     */
    protected function clearUserCache(int $userId): void
    {
        // 清除用户详情缓存
        Cache::delete(self::CACHE_PREFIX . 'info_' . $userId);

        // 清除用户列表缓存
        $this->userModel->clearCache('user_list');

        // 清除统计缓存
        Cache::delete(self::CACHE_PREFIX . 'stat_count');

        // 可以根据需要清除更多缓存
    }

    /**
     * 获取用户选择列表
     *
     * @param array $where 额外条件
     * @return array
     */
    public function getUserOptions(array $where = []): array
    {
        $cacheKey = self::CACHE_PREFIX . 'options_' . md5(serialize($where));
        $options = Cache::get($cacheKey);

        if ($options === null) {
            $query = $this->userModel->where('status', 1)->where($where);
            $users = $query->field('id, name, username, did')->select();

            $options = [];
            foreach ($users as $user) {
                $options[] = [
                    'value' => $user['id'],
                    'label' => $user['name'] . ($user['username'] ? " ({$user['username']})" : '')
                ];
            }

            Cache::set($cacheKey, $options, 1800);
        }

        return $options;
    }

    /**
     * 获取用户统计数据
     *
     * @return array
     */
    public function getUserStatistics(): array
    {
        $cacheKey = self::CACHE_PREFIX . 'statistics';
        $stats = Cache::get($cacheKey);

        if ($stats === null) {
            $stats = [
                'total' => $this->userModel->count(),
                'active' => $this->userModel->where('status', 1)->count(),
                'locked' => $this->userModel->where('is_lock', 1)->count(),
                'new_today' => $this->userModel->where('create_time', '>=', strtotime('today'))->count(),
                'by_department' => [],
                'by_position' => [],
                'by_user_type' => []
            ];

            // 按部门统计
            $deptStats = Db::table('oa_admin')
                ->alias('a')
                ->leftJoin('oa_department d', 'a.did = d.id')
                ->where('a.status', '>', 0)
                ->group('a.did')
                ->field('d.title as department, COUNT(*) as count')
                ->select();
            $stats['by_department'] = $deptStats;

            // 按职位统计
            $posStats = Db::table('oa_admin')
                ->alias('a')
                ->leftJoin('oa_position p', 'a.position_id = p.id')
                ->where('a.status', '>', 0)
                ->group('a.position_id')
                ->field('p.title as position, COUNT(*) as count')
                ->select();
            $stats['by_position'] = $posStats;

            // 按用户类型统计
            $typeStats = Db::table('oa_admin')
                ->where('status', '>', 0)
                ->group('user_type')
                ->field('user_type, COUNT(*) as count')
                ->select();
            foreach ($typeStats as &$item) {
                $item['type'] = $this->getUserTypeText($item['user_type']);
            }
            $stats['by_user_type'] = $typeStats;

            Cache::set($cacheKey, $stats, 3600);
        }

        return $stats;
    }
}
